function WWL ( type, instance_name )
{
	this.class_name = "";

	/* REFINE WHEN NEEDED */
	this.to_string = function ()
	{
		var s = '', id;

		s = '<div class="wwl_' + this.type + '"><div id="' + this.id + '" ';

		s += this.mk_events ();

                s += ' class="' + WWL.mk_class_str ( this, ( this._is_disabled ? "disabled" : null ) ) + '">';
		s += this.name;
                s += '</div></div>';

		return s;
	};

	/* DO NOT TOUCH !! */
	this.type = type;
	this.name = instance_name;
	this.id	  = type + ":" + instance_name;

	this._events = {};
	this._is_disabled = false;
	this._dest_id = null;
	this._blocked_events = {};

	this._event_names = [ 'over', 'out', 'btn_up', 'btn_down', 'click', 'dblclick', 'blur' ];
	this.cbacks = {
		"pre-render" : null,
		"render" : null
	};

	this._rendered = false;

	this.set_event 	  = function ( name, cback ) { this._events [ name ] = cback; };
	this.block_event  = function ( name, mode )  { this._blocked_events [ name ] = mode; };

	this.send_event = function ( evt_name )
	{
		WWL.evt ( null, document.getElementById ( this.id ), evt_name, this );
	};

	this.mk_events = function ()
	{
		var s = '';
		var t, l = this._event_names.length;
		var evt_name, map_name;

		for ( t = 0; t < l; t ++ )
		{
			evt_name = this._event_names [ t ];
			map_name = WWL._event_remap [ evt_name ];
			if ( ! map_name ) map_name = evt_name;

			s += ' on' + map_name + '="return WWL.evt(event,this,\'' + evt_name + '\')" ';
		}

		return s;
	};

	this.disable = function ( is_disabled )
	{
		this._is_disabled = is_disabled;
		this.render ();
	};

	this.render = function ( html_id )
	{
		if ( this.cbacks [ 'pre-render' ] && ( this.cbacks [ 'pre-render' ] ( this ) ) ) return;

		var s = '', id;
		var el;

		this._rendered = false;

		if ( ! html_id ) html_id = this._dest_id;
		this._dest_id = $el ( html_id );

		if ( html_id )
		{
			// Ho l'id giusto
			el = this._dest_id; 

			if ( ! el )
			{
				console.error ( "ERROR: element with id: '" + this._dest_id + "' does not exists" );
				return;
			}
		} else {
			// No HTML ID e no dest_id
			if ( ! this.id )
			{
				console.error ( "ERROR: element %s does not have dest_id or this.id", this.name );
				return;
			}
			el = document.getElementById ( this.id );

			if ( ! el ) return;

			el = el.parentNode;
		}

		el.innerHTML = this.to_string ();
		this._rendered = true;

		if ( this.cbacks [ 'render' ] ) this.cbacks [ 'render' ] ( this );
	};

	this.value = function ( new_val )
	{
		var el = document.getElementById ( this.id );
		var old_val = el.value;

		if ( new_val !== undefined )
		{
			if ( new_val != old_val )
			{
				el.value = new_val;
				// WWL.evt ( null, el, 'change', this );
				this.send_event ( 'change' );
			}
		}

		return old_val;
	};

	WWL._instances [ type + ":" + instance_name ] = this;
}

WWL._instances = {};
WWL._int_events = {};
WWL._event_remap = {
			"over"  : "mouseover",
			"out"   : "mouseout",
			"btn_up" : "mouseup",
			"btn_down" : "mousedown"
		   };

WWL.get_instance = function ( type, instance_name )
{
	return WWL._instances [ type + ":" + instance_name ];
};

WWL.evt = function ( evt, div, event_name, widget )
{
	var event_result = null;

	if ( ! widget ) widget = WWL._resolve_widget ( div.id ); // WWL._instances [ div.id ];

	if ( widget._is_disabled ) return false;
	if ( widget._blocked_events [ event_name ] ) return false;

	// widget.className = widget.className ( /evt_[a-zA-Z0-9]*/, "" );
	// div.className = "wwl " + widget.type + " " + widget.class_name;

	// if ( WWL [ widget.type ]._int_events && WWL [ widget.type ]._int_events [ event_name ] ) WWL [ widget.type ]._int_events [ event_name ] ( widget, div, evt );
	if ( widget._events [ "before-" + event_name ] ) event_result = widget._events [ "before-" + event_name ] ( widget, event_name, div, evt );
	if ( widget._int_events && widget._int_events [ event_name ] ) widget._int_events [ event_name ] ( widget, div, evt );
	if ( widget._events [ event_name ] ) event_result = widget._events [ event_name ] ( widget, event_name, div, evt );

	if ( event_result === null ) event_result = true;

	return event_result === null ? true : event_result;
};

WWL._resolve_widget = function ( id_name )
{
	var w = WWL._instances [ id_name ];
	if ( w ) return w;

	var lst = id_name.split ( ":" );
	var name;
	lst.pop ();

	while ( lst.length )
	{
		name = lst.join ( ":" );
		w = WWL._instances [ name ];
		if ( w ) return w;
	}

	return null;
};

WWL.get_char_code = function ( evt )
{
        evt = ( evt ) ? evt : event;

        // if ( evt.charCode < 32 ) return true;
                
        return ( evt.charCode ) ? evt.charCode : ( ( evt.which ) ? evt.which : evt.keyCode );
};

WWL.get_char = function ( evt )
{
	var ccode = WWL.get_char_code ( evt );

	if ( ccode < 32 ) return null;

        return String.fromCharCode ( ccode );
};

// Automagically includes dependencies
// example: WWL.include ( 'button' );
//
// This function requires liwe.js module
WWL.include = function ( module_name )
{
	var wait_str = "WWL." + module_name;

	if ( liwe.utils.is_def ( wait_str ) ) return;

	liwe.utils.append_js ( module_name + ".js" );
};

WWL.mk_class_str = function ( widget, class_name )
{
	var s = ( widget.class_name ? 
			( widget.class_name  + ( class_name ? "_" + class_name : "" ) ) :
			( class_name ? class_name : "" ) );

	return s;
};

WWL._libbase = "";

WWL.set_libbase = function ( libbase_url )
{
	if ( libbase_url )
	{
		WWL._libbase = libbase_url;
		return;
	}

	var scripts = document.getElementsByTagName ( "script" );
	var l = scripts.length;
	var t, s, pos, path = "";

	for ( t = 0; t < l; t ++ )
	{
		s = scripts [ t ].src;

		if ( ! s ) continue;

		if ( s.match ( /wwl.js/ ) )
		{
			pos = s.lastIndexOf ( "/" );
			if ( pos != -1 ) path = s.slice ( 0, pos + 1 );
		}
	}

	if ( path ) WWL._libbase = path;
	else WWL._libbase = "/os3wwl";
};

WWL.set_libbase ();
